其他
符号执行去除BR指令混淆
一
开篇
二
正文
2.1 获取符号执行的后的地址
src2 = sb.eval_expr(symbolic_pc.src2).arg
2.2 符号执行hook
"""
Symbolic execution of the @irb on the current state
@irb: irbloc instance
@step: display intermediate steps
"""
for assignblk in irb:
self.pc = assignblk.instr.offset
self.instr = assignblk.instr
if step:
print(hex(assignblk.instr.offset) + ":", assignblk.instr)
print('Assignblk:')
print(assignblk)
print('_' * 80)
self.eval_updt_assignblk(assignblk)
if assignblk.instr.offset in self.jmp_dict.keys():
self.symbols.symbols_id[ExprId("PC", 64)] = self.eval_expr(self.jmp_dict[assignblk.instr.offset])
self.symbols.symbols_id[ExprId("IRDst", 64)] = self.eval_expr(self.jmp_dict[assignblk.instr.offset])
2.3 符号执行中断问题
block, next1 = mdis._dis_block(offset)
asmcfg.add_block(block)
2.4 分支遍历不完整问题
condition_pc = []
for i in range(len(asm)):
ins = asm[i]
if ins.mnemonic == "br":
# 开始向上寻找
for j in range(i, 0, -1):
magic_ins = asm[j]
if magic_ins.mnemonic == magic.lower():
condition_pc.append(magic_ins.address)
break
if i - j > 10:
raise Exception("check this br" + str(ins))
return condition_pc
"""
Symbolic execution of the @irb on the current state
@irb: irbloc instance
@step: display intermediate steps
"""
for assignblk in irb:
self.pc = assignblk.instr.offset
self.instr = assignblk.instr
if step:
print(hex(assignblk.instr.offset) + ":", assignblk.instr)
print('Assignblk:')
print(assignblk)
print('_' * 80)
if assignblk.instr.offset in self.condition_pc:
# handle cesl
assigns_key = next(iter(assignblk._assigns.keys()))
assigns_value = assignblk._assigns[assigns_key]
assignblk._assigns[assigns_key] = replace_exprcond2(assigns_value)
self.eval_updt_assignblk(assignblk)
if assignblk.instr.offset in self.jmp_dict.keys():
self.symbols.symbols_id[ExprId("PC", 64)] = self.eval_expr(self.jmp_dict[assignblk.instr.offset])
self.symbols.symbols_id[ExprId("IRDst", 64)] = self.eval_expr(self.jmp_dict[assignblk.instr.offset])
if isinstance(expr, ExprCond):
# 对条件表达式的每个分支进行递归替换
src1 = replace_exprcond2(expr.src1)
src2 = replace_exprcond2(expr.src2)
# 生成两个新的表达式,分别代表条件成立或不成立的情况
return ExprCond(ExprId("SuperMan", 64), src1, src2)
elif isinstance(expr, ExprOp):
# 对ExprOp的每个参数进行递归替换
parts = [replace_exprcond2(arg) for arg in expr.args]
ret = ExprOp(expr.op, *parts)
return ret
else:
# 对于其他类型的表达式(如ExprId, ExprInt等),直接返回
return expr
2.5 递归进行分支树的遍历
print("[*]*****************************************************************")
sb, ircfg = init_machine(blocks, condition, jmp_dict)
try:
symbolic_pc = sb.run_at(ircfg, start_addr, step=True)
except Exception as e:
print("--------Exception---------")
print(e)
return
if symbolic_pc is not None and str(symbolic_pc) != "LR":
if not symbolic_pc.is_cond():
pc = sb.pc
if type(symbolic_pc.arg) == int:
next_pc = symbolic_pc.arg
# fp.write(f"{hex(pc)},{hex(next_pc)}\n")
if next_pc not in blocks and next_pc < end_addr:
blocks.append(next_pc)
handle(blocks, condition, jmp_dict)
else:
expr_list = replace_exprcond(symbolic_pc)
next_pc_list = []
for expr in expr_list:
simp_expr = sb.eval_expr(sb.expr_simp(expr))
if simp_expr not in next_pc_list:
next_pc_list.append(simp_expr)
if len(next_pc_list) == 2:
src1 = next_pc_list[0].arg
src2 = next_pc_list[1].arg
if src1 not in blocks and src1 < end_addr:
blocks.append(src1)
jmp_dict[pc] = next_pc_list[0]
handle(blocks, condition, jmp_dict)
if src2 not in blocks and src2 < end_addr:
blocks.append(src2)
jmp_dict[pc] = next_pc_list[1]
handle(blocks, condition, jmp_dict)
elif len(next_pc_list) == 1:
next_pc = next_pc_list[0].arg
if next_pc not in blocks and next_pc < end_addr:
blocks.append(next_pc)
handle(blocks, condition, jmp_dict)
else:
raise Exception("you need check your code")
else:
pc = sb.pc
src1 = sb.eval_expr(symbolic_pc.src1).arg
src2 = sb.eval_expr(symbolic_pc.src2).arg
# fp.write(f"{hex(pc)},{hex(src1)},{hex(src2)}\n")
if src1 not in blocks and src1 < end_addr:
blocks.append(src1)
jmp_dict[pc] = symbolic_pc.src1
handle(blocks, condition, jmp_dict)
if src2 not in blocks and src2 < end_addr:
blocks.append(src2)
jmp_dict[pc] = symbolic_pc.src2
handle(blocks, condition, jmp_dict)
"""
Symbolic execution of the @irb on the current state
@irb: irbloc instance
@step: display intermediate steps
"""
for assignblk in irb:
self.pc = assignblk.instr.offset
self.instr = assignblk.instr
if step:
print(hex(assignblk.instr.offset) + ":", assignblk.instr)
print('Assignblk:')
print(assignblk)
print('_' * 80)
if assignblk.instr.offset in self.condition_pc:
# handle cesl
assigns_key = next(iter(assignblk._assigns.keys()))
assigns_value = assignblk._assigns[assigns_key]
assignblk._assigns[assigns_key] = replace_exprcond2(assigns_value)
self.eval_updt_assignblk(assignblk)
if assignblk.instr.offset in self.jmp_dict.keys():
self.symbols.symbols_id[ExprId("PC", 64)] = self.eval_expr(self.jmp_dict[assignblk.instr.offset])
self.symbols.symbols_id[ExprId("IRDst", 64)] = self.eval_expr(self.jmp_dict[assignblk.instr.offset])
if step:
self.dump(mems=False)
'''
内存打印太多了
'''
# if assignblk.instr.offset == 0xca768:
# self.dump(ids=False)
print('_' * 80)
if assignblk.instr.name == "BR":
symbolic_pc = self.symbols.symbols_id[assignblk.instr.args[0]]
if not symbolic_pc.is_cond():
pc = self.pc
if type(symbolic_pc.arg) == int:
next_pc = symbolic_pc.arg
self.write(f"{hex(pc)},{hex(next_pc)}\n")
else:
expr_list = replace_exprcond(symbolic_pc)
next_pc_list = []
for expr in expr_list:
simp_expr = self.eval_expr(self.expr_simp(expr))
if simp_expr not in next_pc_list:
next_pc_list.append(simp_expr)
if len(next_pc_list) == 2:
src1 = next_pc_list[0].arg
src2 = next_pc_list[1].arg
self.write(f"{hex(pc)},{hex(src1)},{hex(src2)}\n")
elif len(next_pc_list) == 1:
next_pc = next_pc_list[0].arg
self.write(f"{hex(pc)},{hex(next_pc)}\n")
else:
raise Exception("you need check your code")
else:
pc = self.pc
src1 = int(str(self.eval_expr(symbolic_pc.src1)), 16)
src2 = int(str(self.eval_expr(symbolic_pc.src2)), 16)
self.write(f"{hex(pc)},{hex(src1)},{hex(src2)}\n")
dst = self.eval_expr(self.lifter.IRDst)
return dst
2.6 patch文件
import capstone
import ida_bytes
import idc
from module.utils import MAGIC
KS = keystone.Ks(keystone.KS_ARCH_ARM64, keystone.KS_MODE_LITTLE_ENDIAN)
CS = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)
NOP_BYTES = b'\x1f\x20\x03\xd5'
def handle_txt(path):
addr_dict = {}
f = open(path)
line = f.readline().replace("\n", "")
while line:
info = line.split(",")
if len(info) == 2:
patch_addr = info[0]
b_addr = info[1]
if patch_addr not in addr_dict.keys():
addr_dict[patch_addr] = [b_addr]
else:
addr_list = addr_dict[patch_addr]
if b_addr not in addr_list:
addr_dict[patch_addr].append(b_addr)
elif len(info) == 3:
patch_addr = info[0]
b_addr1 = info[1]
b_addr2 = info[2]
if patch_addr not in addr_dict.keys():
addr_dict[patch_addr] = [b_addr1, b_addr2]
else:
addr_list = addr_dict[patch_addr]
if b_addr1 not in addr_list:
addr_dict[patch_addr].append(b_addr1)
if b_addr2 not in addr_list:
addr_dict[patch_addr].append(b_addr1)
else:
raise Exception("check your code")
line = f.readline().replace("\n", "")
f.close()
return addr_dict
def get_b_const_bytes(ea, const):
'''
返回例如 ea: b 0x12334的指令
:param ea:
:param const:
:return:
'''
ea = int(ea, 16)
CODE = f"b {const[0]}"
encoding, count = KS.asm(CODE, ea)
return ea, bytes(encoding)
def find_magic(ea):
for i in range(10):
asm = idc.GetDisasm(ea)
if asm.startswith(MAGIC):
info = asm.split(",")
cond = info[-1].replace(" ","").lower()
return ea, cond
ea = idc.prev_head(ea)
raise Exception("check your code:" + hex(ea))
def get_bxx_const_bytes(ea, const_list):
ea = int(ea, 16)
patch_ea, cond = find_magic(ea)
code = f"b{cond} {const_list[0]}"
encoding, count = KS.asm(code, patch_ea)
ret = bytes(encoding)
code = f"b {const_list[1]}"
encoding, count = KS.asm(code, patch_ea + 4)
ret += bytes(encoding)
return patch_ea, ret
addr_dict = handle_txt("./addr.txt")
for key in addr_dict.keys():
value = addr_dict[key]
if len(value) == 1:
ea, patch_bytes = get_b_const_bytes(key, value)
ida_bytes.patch_bytes(ea, patch_bytes)
else:
ea, patch_bytes = get_bxx_const_bytes(key, value)
ida_bytes.patch_bytes(ea, patch_bytes)
三
总结
看雪ID:大帅锅
https://bbs.kanxue.com/user-home-759174.htm
# 往期推荐
4、Chrome v8漏洞 CVE-2021-30632浅析
5、CVE-2022-2588 Dirty Cred漏洞分析与复现
球分享
球点赞
球在看
点击阅读原文查看更多